uniform sampler2D depthTexture;
uniform sampler2D noiseTexture;
uniform sampler2D normalTexture;

const float totStrength = 1.38;
const float strength = 0.07;
const float offset = 32.0;
const float falloff = 0.000002;
const float rad = 0.006;

uniform mat4 sceneProj;
#define N_SAMPLES 16
uniform vec3 kernelOffsets[N_SAMPLES];
smooth in vec3 viewRay;

float linearizeDepth(float depth, mat4 projMatrix){
	float zNear = 0.1;
	float zFar = 100.0;
	return (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));

//	return depth;
	return projMatrix[3][2] / (depth - projMatrix[2][2]);
}

vec3 decnorm(vec3 n){
//	return n;
	return n * 2.0 - vec3(1.0);
}

vec4 tex(sampler2D text, vec2 coord){
	coord.x = 1.0 - coord.x;
	coord.y = 1.0 - coord.y;
	return texture(text, coord);
}

float ssao(vec3 norm, vec3 fres, float currentPixelDepth, float radD){
	float bl;
	vec3 ray, se, occNorm;
	float occluderDepth, depthDifference, normDiff, occDepth;
	int i;

	// current fragment coords in screen space
	vec3 ep = vec3(ge_TexCoord0.st, currentPixelDepth);

	for(i=0; i<N_SAMPLES; i++){
		ray = radD * reflect(kernelOffsets[i], fres);
		//ray *= max(0.25, currentPixelDepth);
		//ray = ray * norm;

		se = ep + sign(dot(ray, norm)) * ray;
		//se = ep + dot(ray, norm) * ray;

		occNorm = decnorm(texture(normalTexture, se.xy).xyz);
		occDepth = texture(depthTexture, se.xy).r;
		occDepth = linearizeDepth(occDepth, sceneProj);

		depthDifference = currentPixelDepth - occDepth;
		normDiff = (1.0 - dot(occNorm, norm));

		float v = step(falloff, depthDifference) * normDiff;
		//if(depthDifference > 0.05){
			v *= 1.0 - depthDifference * 10.0;
		//}

		//bl += v;
//		bl += v * (1.0 - smoothstep(falloff, strength, depthDifference));
		float rangeCheck = depthDifference < radD ? 1.0 : 0.0;
		bl += v * rangeCheck;
	}

	float ret = 1.0 - totStrength * bl * (1.0 / float(N_SAMPLES));
	//return 1.0 - clamp(pow(ret, 2.0), 0.0, 1.0);
//	ret = max(0.5, ret * 2.0);
	ret = max(0.5, pow(ret * 2.0, 2.0));
	return ret;
}

void main(){
	float currentPixelDepth = texture(depthTexture, ge_TexCoord0.st).r;
	if(currentPixelDepth >= 1.0){
		ge_FragColor = vec4(1.0);
	}else{
		vec3 fres = texture(noiseTexture, ge_TexCoord0.st * offset).xyz * 2.0 - vec3(1.0);
		fres = normalize(fres);

		vec4 currentPixelSample = texture(normalTexture, ge_TexCoord0.st);
		currentPixelDepth = linearizeDepth(currentPixelDepth, sceneProj);

		// get the normal of current fragment
		vec3 norm = normalize(decnorm(currentPixelSample.xyz));

		// adjust for the depth ( not shure if this is good..)
		float radD = rad / currentPixelDepth;

		float f = ssao(norm, fres, currentPixelDepth, radD);

		ge_FragColor = vec4(f, f, f, 1.0);
	}

/*
	float zNear = 0.1;
	float zFar = 100.0;
	float base_depth = (2.0 * zNear) / (zFar + zNear - texture(depthTexture, ge_TexCoord0.st).x * (zFar - zNear));
	ge_FragColor = texture(normalTexture, ge_TexCoord0.st) * base_depth;
*/
}
